suppressPackageStartupMessages({

library(ArchR)
library(chromVAR)
library(tidyverse)
library(SingleCellExperiment)
library(zellkonverter)
library(dtwclust)
library(BSgenome.Mmusculus.UCSC.mm10)
library(motifmatchr)
library(chromVARmotifs)
})
dir_path <- "/omics/groups/OE0533/internal/katharina/scDoRI/gastrulation_data/jupyter_notebooks/SEACell_files/SEA_aggregates_to_R/"
proj <- loadArchRProject("11_added_Ricards_peaks_p2g_entire_chromosome/")
## Successfully loaded ArchRProject!
## 
##                                                    / |
##                                                  /    \
##             .                                  /      |.
##             \\\                              /        |.
##               \\\                          /           `|.
##                 \\\                      /              |.
##                   \                    /                |\
##                   \\#####\           /                  ||
##                 ==###########>      /                   ||
##                  \\##==......\    /                     ||
##             ______ =       =|__ /__                     ||      \\\
##         ,--' ,----`-,__ ___/'  --,-`-===================##========>
##        \               '        ##_______ _____ ,--,__,=##,__   ///
##         ,    __==    ___,-,__,--'#'  ==='      `-'    | ##,-/
##         -,____,---'       \\####\\________________,--\\_##,/
##            ___      .______        ______  __    __  .______      
##           /   \     |   _  \      /      ||  |  |  | |   _  \     
##          /  ^  \    |  |_)  |    |  ,----'|  |__|  | |  |_)  |    
##         /  /_\  \   |      /     |  |     |   __   | |      /     
##        /  _____  \  |  |\  \\___ |  `----.|  |  |  | |  |\  \\___.
##       /__/     \__\ | _| `._____| \______||__|  |__| | _| `._____|
## 
peaks <- getPeakSet(proj)
class(peaks)
## [1] "GRanges"
## attr(,"package")
## [1] "GenomicRanges"

Add celltypes to motif deviations

Color Palette:

colPalette_celltypes = c('#532C8A',
 '#c19f70',
 '#f9decf',
 '#c9a997',
 '#B51D8D',
 '#3F84AA',
 '#9e6762',
 '#354E23',
 '#F397C0',
 '#ff891c',
 '#635547',
 '#C72228',
 '#f79083',
 '#EF4E22',
 '#989898',
 '#7F6874',
 '#8870ad',
 '#647a4f',
 '#EF5A9D',
 '#FBBE92',
 '#139992',
 '#cc7818',
 '#DFCDE4',
 '#8EC792',
 '#C594BF',
 '#C3C388',
 '#0F4A9C',
 '#FACB12',
 '#8DB5CE',
 '#1A1A1A',
 '#C9EBFB',
 '#DABE99',
 '#65A83E',
 '#005579',
 '#CDE088',
 '#f7f79e',
 '#F6BFCB')

celltypes <- (as.data.frame(getCellColData(proj)) %>% group_by(celltypes) %>% 
 summarise(n = n()))$celltypes

col <- setNames(colPalette_celltypes, celltypes)

SEACell Peak matrix

Based on the SEACell metacells, we created an aggregated peak matrix which we read into R and create a SummarizedExperiment for downstream analysis.

atac_agg_rowData <- read_csv(paste0(dir_path, "atac_agg_rowData.csv"))
atac_agg_rowData <- atac_agg_rowData %>% column_to_rownames("...1") 
atac_agg_colData <- read_csv(paste0(dir_path, "atac_agg_colData.csv"))
atac_agg_colData <- atac_agg_colData %>% column_to_rownames("...1")
peak_agg_matrix <- as.matrix(read_csv(paste0(dir_path, "peak_agg_matrix.csv")))
peak_agg_matrix <- t(peak_agg_matrix)
dim(peak_agg_matrix)

atac_peak_names <- read_csv(paste0(dir_path, "atac_peak_names.csv"))
atac_cell_names <- read_csv(paste0(dir_path, "atac_cell_names.csv"))

rownames(peak_agg_matrix) <- atac_peak_names$`0`
colnames(peak_agg_matrix) <- atac_cell_names$`0`
peak_agg_matrix[1:5, 1:5]

Below you can see the GRanges object for our peaks:

peaks %>% head
## GRanges object with 6 ranges and 4 metadata columns:
##                        seqnames          ranges strand |     score       idx
##                           <Rle>       <IRanges>  <Rle> | <numeric> <integer>
##   chr1:3035600-3036200     chr1 3035600-3036200      * |  11.52670         1
##   chr1:3062691-3063291     chr1 3062691-3063291      * |  12.59330         2
##   chr1:3072272-3072872     chr1 3072272-3072872      * |   9.29753         3
##   chr1:3191513-3192113     chr1 3191513-3192113      * |   7.86981         4
##   chr1:3466250-3466850     chr1 3466250-3466850      * |  12.11960         5
##   chr1:3482737-3483337     chr1 3482737-3483337      * |  32.71030         6
##                               GC         N
##                        <numeric> <numeric>
##   chr1:3035600-3036200    0.4160         0
##   chr1:3062691-3063291    0.4493         0
##   chr1:3072272-3072872    0.3677         0
##   chr1:3191513-3192113    0.4060         0
##   chr1:3466250-3466850    0.4126         0
##   chr1:3482737-3483337    0.4160         0
##   -------
##   seqinfo: 20 sequences from an unspecified genome; no seqlengths

Create a Summarized Experiments from the SEACell aggregate peak matrix

peak_sea <- SummarizedExperiment(assays = list(counts = peak_agg_matrix),
                                 rowRanges = peaks,
                                 colData = atac_agg_colData)

colnames(colData(peak_sea)) <- c("depth")

#saveRDS(peak_sea, paste0(dir_path, "sea_peak_sce.Rds"))
peak_sea <- readRDS(paste0(dir_path, "sea_peak_sce.Rds"))

peak_sea
## class: RangedSummarizedExperiment 
## dim: 180499 613 
## metadata(0):
## assays(1): counts
## rownames(180499): chr1:3035600-3036200 chr1:3062691-3063291 ...
##   chrX:169915632-169916232 chrX:169925539-169926139
## rowData names(4): score idx GC N
## colnames(613): E8.0_rep2#CGCATTTGTTGCATCT-1
##   E8.75_rep1#AGTGCCGGTTAGGTTG-1 ... E8.75_rep1#AATCGCCCATACTCCT-1
##   E8.0_rep2#AGCAGGTAGCTTCCCG-1
## colData names(1): depth

ChromVar Motif deviations

Add GC bias

peak_sea <- addGCBias(peak_sea,
                      genome = BSgenome.Mmusculus.UCSC.mm10)

Get motifs & match motifs with peaks

Here we use the motif annotations from ArchR, in order to be able to better compare the annotations with the ArchR deviation results on single cells.

proj <- addMotifAnnotations(ArchRProj = proj, motifSet = "cisbp", name = "Motif")

motifs <- getPeakAnnotation(proj, "Motif")
motif_ix <- matchMotifs(motifs$motifs, # motif pwm matrix
                        peak_sea, # peak accessibility matrix
                        genome = BSgenome.Mmusculus.UCSC.mm10) # genome

Compute deviations

dev <- computeDeviations(object = peak_sea, annotations = motif_ix)
dev


# remove index number from TFs
rownames(dev) <- str_remove(rownames(dev), "_(?=[0-9])")


variability <- computeVariability(dev)


#saveRDS(dev, paste0(dir_path, "SEACell_ChromVarDev"))
#saveRDS(variability, paste0(dir_path, "SEACell_ChromVarDev_variability"))


write.csv(deviations(dev), paste0(dir_path, "deviations.csv"))
write.csv(deviationScores(dev), paste0(dir_path, "deviationScores.csv"))
write.csv(variability, paste0(dir_path, "variability.csv"))

SEACell ChromVar Deviations

# read in the deviations
dev <- readRDS(paste0(dir_path, "SEACell_ChromVarDev"))

variability <- readRDS(paste0(dir_path, "SEACell_ChromVarDev_variability"))

Celltype distributions

sea_archr_meta <- read_csv("/omics/groups/OE0533/internal/katharina/scDoRI/gastrulation_data/jupyter_notebooks/SEACell_files/archr_sea_metadata.csv")
## Rows: 45986 Columns: 22
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr  (4): index, Sample, celltypes, SEACell
## dbl (18): TSSEnrichment, ReadsInTSS, ReadsInPromoter, ReadsInBlacklist, Prom...
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
celltype_df <- sea_archr_meta %>%
  dplyr::count(SEACell, celltypes) %>%
  dplyr::group_by(SEACell) %>%
  slice_max(order_by=n, n=1, with_ties = FALSE) %>% 
  select(SEACell, celltypes)
  
# sea_archr_meta %>%
#   dplyr::count(SEACell, celltypes) %>%
#   dplyr::group_by(SEACell) %>%
#   slice_max(order_by=n, n=1) %>% 
#   pull(celltypes, SEACell) %>% head

p1 <- celltype_df %>% 
  ggplot() + geom_bar(aes(x = celltypes, fill = celltypes)) +
    theme(legend.position = "None",
        axis.title.x=element_blank(),
        axis.text.x=element_blank(),
        axis.ticks.x=element_blank()) +
  scale_fill_manual(values = col) +
  labs(title = "Number of metacells with particular celltype")

p2 <- sea_archr_meta %>%
  ggplot() +
  geom_bar(aes(x = celltypes, fill = celltypes)) +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1), legend.position = "None") +
  scale_fill_manual(values = col) 
  labs(title = "Number of single cells with particular celltype")
## $title
## [1] "Number of single cells with particular celltype"
## 
## attr(,"class")
## [1] "labels"
cowplot::plot_grid(p1, p2, ncol = 1)

Purity of SEACells

x <- (sea_archr_meta %>% group_by(SEACell) %>%
                    summarise(cell_n = n()) %>%
                    ungroup())$cell_n

y <- (sea_archr_meta %>%
        
  dplyr::count(SEACell, celltypes) %>%
  dplyr::group_by(SEACell) %>%
  slice_max(order_by=n, n=1, with_ties = FALSE))$n


ggplot() + 
  geom_point(aes (x = x,
                  y = y)) +
  geom_line(aes(x = x, y = x, color = "orange")) +
  geom_line(aes(x = x, y = x * 0.8), color = "blue") +
  theme(legend.position = "None") +
  labs(x = "Number of single cells per SEACell",
       y = "Number of single cells with most common celltype per SEACell")

x <- (sea_archr_meta %>% filter(SEACell %in%
                            (celltype_df %>% filter(celltypes == "Cardiomyocytes"))$SEACell) %>% 
  group_by(SEACell) %>%
  summarise(cell_n = n() ) %>% ungroup())$cell_n

y = (sea_archr_meta %>%
       filter(SEACell %in% (celltype_df %>% filter(celltypes == "Cardiomyocytes"))$SEACell) %>% 
  dplyr::count(SEACell, celltypes) %>%
  dplyr::group_by(SEACell) %>%
  slice_max(order_by=n, n=1, with_ties = FALSE))$n

ggplot() + geom_point(aes(x = x, y = y)) + 
  labs(title = "Cardiomyocyte SEACells",
       x = "Number of single cells in metacells",
       y = "Number of cells with Cardiomyocyte label") 

ChromVar Scores for SEACells, GATA Factors

df <- colData(dev) %>% as.data.frame() %>% rownames_to_column("SEACell")
df <- left_join(celltype_df, df, by = "SEACell")


colData(dev) <- DataFrame(df)

motif_mtx <- assays(dev)[[1]]
tfs <- rownames(dev)
metadata <- colData(dev) %>% as.data.frame()
colnames(motif_mtx) <- metadata$SEACell


gatas <- c("Gata1", "Gata2", "Gata3", "Gata4", "Gata5", "Gata6")

plots <- map (gatas, function(n){
  motif_n <- motif_mtx[rownames(motif_mtx) ==  tfs[grepl(paste0("^", n), tfs)], ]
  p2 <- metadata %>%
    mutate(!!n := motif_n) %>%
    group_by(celltypes) %>%
    #summarise_at(vars(n), funs(mean(., na.rm=TRUE)))
    summarise(mean = mean(!!(sym(n)))) %>%
    ggplot() +
    geom_bar(aes(x = celltypes, y = mean, fill = celltypes), stat = "identity") +
    scale_fill_manual(values = col) +
    theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1), legend.position = "None") +#%>% print()
    labs(y = "SEACell deviation score")
  p1 <- metadata %>%
    mutate(!!n := motif_n) %>%
    #group_by(SEACell) %>% #, celltypes) %>%
    #summarise_at(vars(n), funs(mean(., na.rm=TRUE)))
    #summarise(mean = mean(!!(sym(n)))) %>%
    ggplot() +
    geom_boxplot(aes(x = celltypes, y = !!(sym(n)),
                     fill = celltypes)) +
    geom_jitter(aes(x = celltypes,
                    y = !!(sym(n))), color="black", 
                size=0.4, alpha=0.9) +
    # geom_point(aes(x = celltypes, y = !!(sym(n))),
    #                position = position_dodge(width = .5))) +
    scale_fill_manual(values = col) +
    theme(legend.position = "None", 
        axis.title.x=element_blank(),
        axis.text.x=element_blank(),
        axis.ticks.x=element_blank()) +
    labs(title = paste0(n),y = "SEACell deviation score")
  plot <- cowplot::plot_grid(p1, p2, ncol = 1)
})


do.call(what = gridExtra::grid.arrange, args = append(plots, list(ncol = 2)))

n = "Gata1"
motif_n <-  motif_mtx[rownames(motif_mtx) ==  tfs[grepl(paste0("^", n), tfs)], ]
metadata %>%
  mutate(!!n := motif_n) %>%
  ggplot() +
  geom_bar(aes(x = SEACell, y = !!(sym(n))), stat = "identity", width = 5) +
  geom_hline(yintercept = 0) +
  #scale_fill_manual(values = col) +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1), legend.position = "None") +#%>% print()
  labs(title = paste0(n), y = "SEACell deviation score") +
  facet_wrap(~ celltypes, ncol = 3)
## Warning: position_stack requires non-overlapping x intervals
## position_stack requires non-overlapping x intervals
## position_stack requires non-overlapping x intervals
## position_stack requires non-overlapping x intervals
## position_stack requires non-overlapping x intervals
## position_stack requires non-overlapping x intervals
## position_stack requires non-overlapping x intervals
## position_stack requires non-overlapping x intervals
## position_stack requires non-overlapping x intervals
## position_stack requires non-overlapping x intervals
## position_stack requires non-overlapping x intervals
## position_stack requires non-overlapping x intervals
## position_stack requires non-overlapping x intervals
## position_stack requires non-overlapping x intervals
## position_stack requires non-overlapping x intervals
## position_stack requires non-overlapping x intervals
## position_stack requires non-overlapping x intervals
## position_stack requires non-overlapping x intervals
## position_stack requires non-overlapping x intervals
## position_stack requires non-overlapping x intervals
## position_stack requires non-overlapping x intervals
## position_stack requires non-overlapping x intervals
## position_stack requires non-overlapping x intervals
## position_stack requires non-overlapping x intervals
## position_stack requires non-overlapping x intervals
## position_stack requires non-overlapping x intervals
## position_stack requires non-overlapping x intervals
## position_stack requires non-overlapping x intervals
## position_stack requires non-overlapping x intervals
## position_stack requires non-overlapping x intervals
## position_stack requires non-overlapping x intervals

metadata %>%
  mutate(!!n := motif_n) %>%
  filter(celltypes == "Cardiomyocytes")
##                         SEACell      celltypes     depth        Gata1
## 1  E8.5_rep1#GTAGTTTCAGCACGAA-1 Cardiomyocytes  9064.933  0.012132169
## 2  E8.5_rep2#CAAGTATGTAATGACT-1 Cardiomyocytes 10973.384 -0.008163193
## 3  E8.5_rep2#TTGTTCCCATGGTTAT-1 Cardiomyocytes 15322.527 -0.010098280
## 4 E8.75_rep1#AGGCCCAGTACCAGGT-1 Cardiomyocytes  5357.824 -0.009610496
## 5 E8.75_rep1#GCGCGATTCTTGTTCG-1 Cardiomyocytes 15861.952  0.007847011

Filter for pure SEACells

To check why the deviation scores are worse than expected, I removed any SEACells which are less than 80% pure, meaning that less than 80% of cells belong to the same celltype.

pure_seacells <- (sea_archr_meta %>%  
  dplyr::group_by(SEACell) %>% #head
  mutate(cells_per_SEA = n()) %>% 
  ungroup() %>%
  dplyr::count(SEACell, celltypes, cells_per_SEA) %>%
  dplyr::group_by(SEACell) %>% 
  mutate(percent = n/cells_per_SEA) %>%
  filter(percent > .8))$SEACell

print(paste0("Out of ", nrow(metadata), " SEACells only ", length(pure_seacells), 
             " are above 80% composed of the same celltype."))
## [1] "Out of 613 SEACells only 355 are above 80% composed of the same celltype."
plots <- map(gatas, function(n){
  motif_n <- motif_mtx[rownames(motif_mtx) ==  tfs[grepl(paste0("^", n), tfs)], pure_seacells]
  p2 <- metadata %>%
    filter(SEACell %in% pure_seacells) %>%
    mutate(!!n := motif_n) %>%
    group_by(celltypes) %>%
    summarise(mean = mean(!!(sym(n)))) %>%
    ggplot() +
    geom_bar(aes(x = celltypes, y = mean, fill = celltypes), stat = "identity") +
    theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1), legend.position = "None")+
    scale_fill_manual(values = col) +
    labs( y = "SEACell deviation score")
  p1 <- metadata %>%    
    filter(SEACell %in% pure_seacells) %>%
    mutate(!!n := motif_n) %>%
    ggplot() +
    geom_boxplot(aes(x = celltypes, y = !!(sym(n)), fill = celltypes)) +
    geom_jitter(aes(x = celltypes,
                    y = !!(sym(n))), color="black", 
                size=0.4, alpha=0.9) +
    scale_fill_manual(values = col) +
        theme(legend.position = "None",
        axis.title.x=element_blank(),
        axis.text.x=element_blank(),
        axis.ticks.x=element_blank()) +
    labs(title = paste0(n),y = "SEACell deviation scores")
  plots <- cowplot::plot_grid(p1, p2, ncol = 1)
})

do.call(what = gridExtra::grid.arrange, args = append(plots, list(ncol = 2)))

RNA expression

# add raw counts to python
rna_seurat <- readRDS("Seurat_objects/rna_Seurat_object")
raw_counts<- rna_seurat@assays$originalexp@counts[rna_genes$`0`, ]
write.csv(raw_counts, '/omics/groups/OE0533/internal/katharina/scDoRI/gastrulation_data/jupyter_notebooks/SEACell_files/ArchR_object/raw_gene_expr.csv', quote=FALSE)


rna_mat <- read_csv(paste0(dir_path, "rna_agg_matrix.csv"))
rna_cells <- read_csv(paste0(dir_path, "rna_cell_names.csv"))
rna_genes <- read_csv(paste0(dir_path, "rna_gene_names.csv"))
dim(rna_mat)
rna_mat <- t(rna_mat)

rownames(rna_mat) <- rna_genes$`0`
colnames(rna_mat) <- rna_cells$`0`
  

test <- SummarizedExperiment(assays = list(counts = rna_mat),
                                 #rowRanges = gene_anno,
                                 colData = DataFrame(df))

  
#   
#   
# # normalize counts
# norm_rna_mat <- log1p(t(t(rna_mat) / colSums(rna_mat)) * 1e4)
# #rownames(norm_rna_mat) <- rna_genes$"0"
# colnames(norm_rna_mat) <- rna_cells$"0"

gene_anno <- getGenes(proj) %>% as.data.frame() %>% 
  unite(index, seqnames, start,sep = ":", remove = FALSE) %>%
  unite(index, index, end, sep = "-", remove = FALSE) %>% 
  filter(symbol %in% rna_genes$"0")# %>% #head
  #column_to_rownames(index)
  #column_to_rownames("index") %>%
 # GRanges()

rna_sce <- SummarizedExperiment(assays = list(counts = rna_mat),
                             rowData = gene_anno,
                                 #rowRanges = gene_anno,
                                 colData = DataFrame(df))




rna_mat <- assays(rna_sce)[[1]]

metadata <- colData(rna_sce) %>% as.data.frame()

gatas <- c("Gata1", "Gata2", "Gata3", "Gata4", "Gata5", "Gata6")

for (n in gatas){
  motif_n <- rna_mat[rownames(rna_mat) ==  n, ]#tfs[grepl(paste0("^", n), tfs)], ]
  p <- metadata %>%
    mutate(!!n := motif_n) %>%
    group_by(celltypes) %>%
    #summarise_at(vars(n), funs(mean(., na.rm=TRUE)))
    summarise(mean = mean(!!(sym(n)))) %>%
    ggplot() +
    geom_bar(aes(x = celltypes, y = mean, fill = celltypes), stat = "identity") +
    scale_fill_manual(values = col) +
    theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1), legend.position = "None") +#%>% print()
    labs(title = paste0(n), y = "SEACell  score")
  print(p)
}
LS0tCnRpdGxlOiAiU0VBQ2VsbCBDaHJvbVZhciIKb3V0cHV0OiAKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICB0b2NfZGVwdGg6IDMKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICB0aGVtZTogY29zbW8KICAgIGhpZ2hsaWdodDogdGV4dG1hdGUKLS0tCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoY2FjaGUgPSBGQUxTRSkKa25pdHI6Om9wdHNfa25pdCRzZXQocm9vdC5kaXIgPSAiL29taWNzL2dyb3Vwcy9PRTA1MzMvaW50ZXJuYWwva2F0aGFyaW5hL3NjRG9SSS9nYXN0cnVsYXRpb25fZGF0YSIpCnNldHdkKCIvb21pY3MvZ3JvdXBzL09FMDUzMy9pbnRlcm5hbC9rYXRoYXJpbmEvc2NEb1JJL2dhc3RydWxhdGlvbl9kYXRhIikKc2V0LnNlZWQoMSkKYGBgCgpgYGB7cn0Kc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKHsKCmxpYnJhcnkoQXJjaFIpCmxpYnJhcnkoY2hyb21WQVIpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KFNpbmdsZUNlbGxFeHBlcmltZW50KQpsaWJyYXJ5KHplbGxrb252ZXJ0ZXIpCmxpYnJhcnkoZHR3Y2x1c3QpCmxpYnJhcnkoQlNnZW5vbWUuTW11c2N1bHVzLlVDU0MubW0xMCkKbGlicmFyeShtb3RpZm1hdGNocikKbGlicmFyeShjaHJvbVZBUm1vdGlmcykKfSkKYGBgCgpgYGB7cn0KZGlyX3BhdGggPC0gIi9vbWljcy9ncm91cHMvT0UwNTMzL2ludGVybmFsL2thdGhhcmluYS9zY0RvUkkvZ2FzdHJ1bGF0aW9uX2RhdGEvanVweXRlcl9ub3RlYm9va3MvU0VBQ2VsbF9maWxlcy9TRUFfYWdncmVnYXRlc190b19SLyIKcHJvaiA8LSBsb2FkQXJjaFJQcm9qZWN0KCIxMV9hZGRlZF9SaWNhcmRzX3BlYWtzX3AyZ19lbnRpcmVfY2hyb21vc29tZS8iKQpwZWFrcyA8LSBnZXRQZWFrU2V0KHByb2opCmNsYXNzKHBlYWtzKQpgYGAKCiMgQWRkIGNlbGx0eXBlcyB0byBtb3RpZiBkZXZpYXRpb25zCgpDb2xvciBQYWxldHRlOgoKYGBge3J9CmNvbFBhbGV0dGVfY2VsbHR5cGVzID0gYygnIzUzMkM4QScsCiAnI2MxOWY3MCcsCiAnI2Y5ZGVjZicsCiAnI2M5YTk5NycsCiAnI0I1MUQ4RCcsCiAnIzNGODRBQScsCiAnIzllNjc2MicsCiAnIzM1NEUyMycsCiAnI0YzOTdDMCcsCiAnI2ZmODkxYycsCiAnIzYzNTU0NycsCiAnI0M3MjIyOCcsCiAnI2Y3OTA4MycsCiAnI0VGNEUyMicsCiAnIzk4OTg5OCcsCiAnIzdGNjg3NCcsCiAnIzg4NzBhZCcsCiAnIzY0N2E0ZicsCiAnI0VGNUE5RCcsCiAnI0ZCQkU5MicsCiAnIzEzOTk5MicsCiAnI2NjNzgxOCcsCiAnI0RGQ0RFNCcsCiAnIzhFQzc5MicsCiAnI0M1OTRCRicsCiAnI0MzQzM4OCcsCiAnIzBGNEE5QycsCiAnI0ZBQ0IxMicsCiAnIzhEQjVDRScsCiAnIzFBMUExQScsCiAnI0M5RUJGQicsCiAnI0RBQkU5OScsCiAnIzY1QTgzRScsCiAnIzAwNTU3OScsCiAnI0NERTA4OCcsCiAnI2Y3Zjc5ZScsCiAnI0Y2QkZDQicpCgpjZWxsdHlwZXMgPC0gKGFzLmRhdGEuZnJhbWUoZ2V0Q2VsbENvbERhdGEocHJvaikpICU+JSBncm91cF9ieShjZWxsdHlwZXMpICU+JSAKIHN1bW1hcmlzZShuID0gbigpKSkkY2VsbHR5cGVzCgpjb2wgPC0gc2V0TmFtZXMoY29sUGFsZXR0ZV9jZWxsdHlwZXMsIGNlbGx0eXBlcykKYGBgCgoKCiMgU0VBQ2VsbCBQZWFrIG1hdHJpeAoKQmFzZWQgb24gdGhlIFNFQUNlbGwgbWV0YWNlbGxzLCB3ZSBjcmVhdGVkIGFuIGFnZ3JlZ2F0ZWQgcGVhayBtYXRyaXggd2hpY2ggd2UKcmVhZCBpbnRvIFIgYW5kIGNyZWF0ZSBhIFN1bW1hcml6ZWRFeHBlcmltZW50IGZvciBkb3duc3RyZWFtIGFuYWx5c2lzLgoKYGBgI3tyfQphdGFjX2FnZ19yb3dEYXRhIDwtIHJlYWRfY3N2KHBhc3RlMChkaXJfcGF0aCwgImF0YWNfYWdnX3Jvd0RhdGEuY3N2IikpCmF0YWNfYWdnX3Jvd0RhdGEgPC0gYXRhY19hZ2dfcm93RGF0YSAlPiUgY29sdW1uX3RvX3Jvd25hbWVzKCIuLi4xIikgCmF0YWNfYWdnX2NvbERhdGEgPC0gcmVhZF9jc3YocGFzdGUwKGRpcl9wYXRoLCAiYXRhY19hZ2dfY29sRGF0YS5jc3YiKSkKYXRhY19hZ2dfY29sRGF0YSA8LSBhdGFjX2FnZ19jb2xEYXRhICU+JSBjb2x1bW5fdG9fcm93bmFtZXMoIi4uLjEiKQpwZWFrX2FnZ19tYXRyaXggPC0gYXMubWF0cml4KHJlYWRfY3N2KHBhc3RlMChkaXJfcGF0aCwgInBlYWtfYWdnX21hdHJpeC5jc3YiKSkpCnBlYWtfYWdnX21hdHJpeCA8LSB0KHBlYWtfYWdnX21hdHJpeCkKZGltKHBlYWtfYWdnX21hdHJpeCkKCmF0YWNfcGVha19uYW1lcyA8LSByZWFkX2NzdihwYXN0ZTAoZGlyX3BhdGgsICJhdGFjX3BlYWtfbmFtZXMuY3N2IikpCmF0YWNfY2VsbF9uYW1lcyA8LSByZWFkX2NzdihwYXN0ZTAoZGlyX3BhdGgsICJhdGFjX2NlbGxfbmFtZXMuY3N2IikpCgpyb3duYW1lcyhwZWFrX2FnZ19tYXRyaXgpIDwtIGF0YWNfcGVha19uYW1lcyRgMGAKY29sbmFtZXMocGVha19hZ2dfbWF0cml4KSA8LSBhdGFjX2NlbGxfbmFtZXMkYDBgCnBlYWtfYWdnX21hdHJpeFsxOjUsIDE6NV0KYGBgCkJlbG93IHlvdSBjYW4gc2VlIHRoZSBHUmFuZ2VzIG9iamVjdCBmb3Igb3VyIHBlYWtzOgoKYGBge3J9CnBlYWtzICU+JSBoZWFkCmBgYAoKCkNyZWF0ZSBhIFN1bW1hcml6ZWQgRXhwZXJpbWVudHMgZnJvbSB0aGUgU0VBQ2VsbCBhZ2dyZWdhdGUgcGVhayBtYXRyaXgKCmBgYCN7cn0KcGVha19zZWEgPC0gU3VtbWFyaXplZEV4cGVyaW1lbnQoYXNzYXlzID0gbGlzdChjb3VudHMgPSBwZWFrX2FnZ19tYXRyaXgpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByb3dSYW5nZXMgPSBwZWFrcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sRGF0YSA9IGF0YWNfYWdnX2NvbERhdGEpCgpjb2xuYW1lcyhjb2xEYXRhKHBlYWtfc2VhKSkgPC0gYygiZGVwdGgiKQoKI3NhdmVSRFMocGVha19zZWEsIHBhc3RlMChkaXJfcGF0aCwgInNlYV9wZWFrX3NjZS5SZHMiKSkKYGBgCgoKYGBge3J9CgpwZWFrX3NlYSA8LSByZWFkUkRTKHBhc3RlMChkaXJfcGF0aCwgInNlYV9wZWFrX3NjZS5SZHMiKSkKCnBlYWtfc2VhCmBgYAoKCiMgQ2hyb21WYXIgTW90aWYgZGV2aWF0aW9ucwoKIyMjIEFkZCBHQyBiaWFzCgpgYGB7cn0KcGVha19zZWEgPC0gYWRkR0NCaWFzKHBlYWtfc2VhLAogICAgICAgICAgICAgICAgICAgICAgZ2Vub21lID0gQlNnZW5vbWUuTW11c2N1bHVzLlVDU0MubW0xMCkKCmBgYAoKIyMjIEdldCBtb3RpZnMgJiBtYXRjaCBtb3RpZnMgd2l0aCBwZWFrcwoKSGVyZSB3ZSB1c2UgdGhlIG1vdGlmIGFubm90YXRpb25zIGZyb20gQXJjaFIsIGluIG9yZGVyIHRvIGJlIGFibGUgdG8gYmV0dGVyIApjb21wYXJlIHRoZSBhbm5vdGF0aW9ucyB3aXRoIHRoZSBBcmNoUiBkZXZpYXRpb24gcmVzdWx0cyBvbiBzaW5nbGUgY2VsbHMuIAoKYGBgI3tyfQpwcm9qIDwtIGFkZE1vdGlmQW5ub3RhdGlvbnMoQXJjaFJQcm9qID0gcHJvaiwgbW90aWZTZXQgPSAiY2lzYnAiLCBuYW1lID0gIk1vdGlmIikKCm1vdGlmcyA8LSBnZXRQZWFrQW5ub3RhdGlvbihwcm9qLCAiTW90aWYiKQptb3RpZl9peCA8LSBtYXRjaE1vdGlmcyhtb3RpZnMkbW90aWZzLCAjIG1vdGlmIHB3bSBtYXRyaXgKICAgICAgICAgICAgICAgICAgICAgICAgcGVha19zZWEsICMgcGVhayBhY2Nlc3NpYmlsaXR5IG1hdHJpeAogICAgICAgICAgICAgICAgICAgICAgICBnZW5vbWUgPSBCU2dlbm9tZS5NbXVzY3VsdXMuVUNTQy5tbTEwKSAjIGdlbm9tZQoKYGBgCgojIyMgQ29tcHV0ZSBkZXZpYXRpb25zCgpgYGAje3J9CmRldiA8LSBjb21wdXRlRGV2aWF0aW9ucyhvYmplY3QgPSBwZWFrX3NlYSwgYW5ub3RhdGlvbnMgPSBtb3RpZl9peCkKZGV2CgoKIyByZW1vdmUgaW5kZXggbnVtYmVyIGZyb20gVEZzCnJvd25hbWVzKGRldikgPC0gc3RyX3JlbW92ZShyb3duYW1lcyhkZXYpLCAiXyg/PVswLTldKSIpCgoKdmFyaWFiaWxpdHkgPC0gY29tcHV0ZVZhcmlhYmlsaXR5KGRldikKCgojc2F2ZVJEUyhkZXYsIHBhc3RlMChkaXJfcGF0aCwgIlNFQUNlbGxfQ2hyb21WYXJEZXYiKSkKI3NhdmVSRFModmFyaWFiaWxpdHksIHBhc3RlMChkaXJfcGF0aCwgIlNFQUNlbGxfQ2hyb21WYXJEZXZfdmFyaWFiaWxpdHkiKSkKCgp3cml0ZS5jc3YoZGV2aWF0aW9ucyhkZXYpLCBwYXN0ZTAoZGlyX3BhdGgsICJkZXZpYXRpb25zLmNzdiIpKQp3cml0ZS5jc3YoZGV2aWF0aW9uU2NvcmVzKGRldiksIHBhc3RlMChkaXJfcGF0aCwgImRldmlhdGlvblNjb3Jlcy5jc3YiKSkKd3JpdGUuY3N2KHZhcmlhYmlsaXR5LCBwYXN0ZTAoZGlyX3BhdGgsICJ2YXJpYWJpbGl0eS5jc3YiKSkKYGBgCgoKCiMgIFNFQUNlbGwgQ2hyb21WYXIgRGV2aWF0aW9ucwoKYGBge3J9CiMgcmVhZCBpbiB0aGUgZGV2aWF0aW9ucwpkZXYgPC0gcmVhZFJEUyhwYXN0ZTAoZGlyX3BhdGgsICJTRUFDZWxsX0Nocm9tVmFyRGV2IikpCgp2YXJpYWJpbGl0eSA8LSByZWFkUkRTKHBhc3RlMChkaXJfcGF0aCwgIlNFQUNlbGxfQ2hyb21WYXJEZXZfdmFyaWFiaWxpdHkiKSkKYGBgCgojIyBDZWxsdHlwZSBkaXN0cmlidXRpb25zIAoKYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD04fQpzZWFfYXJjaHJfbWV0YSA8LSByZWFkX2NzdigiL29taWNzL2dyb3Vwcy9PRTA1MzMvaW50ZXJuYWwva2F0aGFyaW5hL3NjRG9SSS9nYXN0cnVsYXRpb25fZGF0YS9qdXB5dGVyX25vdGVib29rcy9TRUFDZWxsX2ZpbGVzL2FyY2hyX3NlYV9tZXRhZGF0YS5jc3YiKQoKCmNlbGx0eXBlX2RmIDwtIHNlYV9hcmNocl9tZXRhICU+JQogIGRwbHlyOjpjb3VudChTRUFDZWxsLCBjZWxsdHlwZXMpICU+JQogIGRwbHlyOjpncm91cF9ieShTRUFDZWxsKSAlPiUKICBzbGljZV9tYXgob3JkZXJfYnk9biwgbj0xLCB3aXRoX3RpZXMgPSBGQUxTRSkgJT4lIAogIHNlbGVjdChTRUFDZWxsLCBjZWxsdHlwZXMpCiAgCiMgc2VhX2FyY2hyX21ldGEgJT4lCiMgICBkcGx5cjo6Y291bnQoU0VBQ2VsbCwgY2VsbHR5cGVzKSAlPiUKIyAgIGRwbHlyOjpncm91cF9ieShTRUFDZWxsKSAlPiUKIyAgIHNsaWNlX21heChvcmRlcl9ieT1uLCBuPTEpICU+JSAKIyAgIHB1bGwoY2VsbHR5cGVzLCBTRUFDZWxsKSAlPiUgaGVhZAoKcDEgPC0gY2VsbHR5cGVfZGYgJT4lIAogIGdncGxvdCgpICsgZ2VvbV9iYXIoYWVzKHggPSBjZWxsdHlwZXMsIGZpbGwgPSBjZWxsdHlwZXMpKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiTm9uZSIsCiAgICAgICAgYXhpcy50aXRsZS54PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueD1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy54PWVsZW1lbnRfYmxhbmsoKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvbCkgKwogIGxhYnModGl0bGUgPSAiTnVtYmVyIG9mIG1ldGFjZWxscyB3aXRoIHBhcnRpY3VsYXIgY2VsbHR5cGUiKQoKcDIgPC0gc2VhX2FyY2hyX21ldGEgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fYmFyKGFlcyh4ID0gY2VsbHR5cGVzLCBmaWxsID0gY2VsbHR5cGVzKSkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdD0xKSwgbGVnZW5kLnBvc2l0aW9uID0gIk5vbmUiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sKSAKICBsYWJzKHRpdGxlID0gIk51bWJlciBvZiBzaW5nbGUgY2VsbHMgd2l0aCBwYXJ0aWN1bGFyIGNlbGx0eXBlIikKCmNvd3Bsb3Q6OnBsb3RfZ3JpZChwMSwgcDIsIG5jb2wgPSAxKQpgYGAKCiMjIFB1cml0eSBvZiBTRUFDZWxscwoKYGBge3J9CnggPC0gKHNlYV9hcmNocl9tZXRhICU+JSBncm91cF9ieShTRUFDZWxsKSAlPiUKICAgICAgICAgICAgICAgICAgICBzdW1tYXJpc2UoY2VsbF9uID0gbigpKSAlPiUKICAgICAgICAgICAgICAgICAgICB1bmdyb3VwKCkpJGNlbGxfbgoKeSA8LSAoc2VhX2FyY2hyX21ldGEgJT4lCiAgICAgICAgCiAgZHBseXI6OmNvdW50KFNFQUNlbGwsIGNlbGx0eXBlcykgJT4lCiAgZHBseXI6Omdyb3VwX2J5KFNFQUNlbGwpICU+JQogIHNsaWNlX21heChvcmRlcl9ieT1uLCBuPTEsIHdpdGhfdGllcyA9IEZBTFNFKSkkbgoKCmdncGxvdCgpICsgCiAgZ2VvbV9wb2ludChhZXMgKHggPSB4LAogICAgICAgICAgICAgICAgICB5ID0geSkpICsKICBnZW9tX2xpbmUoYWVzKHggPSB4LCB5ID0geCwgY29sb3IgPSAib3JhbmdlIikpICsKICBnZW9tX2xpbmUoYWVzKHggPSB4LCB5ID0geCAqIDAuOCksIGNvbG9yID0gImJsdWUiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIk5vbmUiKSArCiAgbGFicyh4ID0gIk51bWJlciBvZiBzaW5nbGUgY2VsbHMgcGVyIFNFQUNlbGwiLAogICAgICAgeSA9ICJOdW1iZXIgb2Ygc2luZ2xlIGNlbGxzIHdpdGggbW9zdCBjb21tb24gY2VsbHR5cGUgcGVyIFNFQUNlbGwiKQoKCgpgYGAKCmBgYHtyLCBmaWcud2lkdGg9MywgZmlnLmhlaWdodD0zfQoKeCA8LSAoc2VhX2FyY2hyX21ldGEgJT4lIGZpbHRlcihTRUFDZWxsICVpbiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgIChjZWxsdHlwZV9kZiAlPiUgZmlsdGVyKGNlbGx0eXBlcyA9PSAiQ2FyZGlvbXlvY3l0ZXMiKSkkU0VBQ2VsbCkgJT4lIAogIGdyb3VwX2J5KFNFQUNlbGwpICU+JQogIHN1bW1hcmlzZShjZWxsX24gPSBuKCkgKSAlPiUgdW5ncm91cCgpKSRjZWxsX24KCnkgPSAoc2VhX2FyY2hyX21ldGEgJT4lCiAgICAgICBmaWx0ZXIoU0VBQ2VsbCAlaW4lIChjZWxsdHlwZV9kZiAlPiUgZmlsdGVyKGNlbGx0eXBlcyA9PSAiQ2FyZGlvbXlvY3l0ZXMiKSkkU0VBQ2VsbCkgJT4lIAogIGRwbHlyOjpjb3VudChTRUFDZWxsLCBjZWxsdHlwZXMpICU+JQogIGRwbHlyOjpncm91cF9ieShTRUFDZWxsKSAlPiUKICBzbGljZV9tYXgob3JkZXJfYnk9biwgbj0xLCB3aXRoX3RpZXMgPSBGQUxTRSkpJG4KCmdncGxvdCgpICsgZ2VvbV9wb2ludChhZXMoeCA9IHgsIHkgPSB5KSkgKyAKICBsYWJzKHRpdGxlID0gIkNhcmRpb215b2N5dGUgU0VBQ2VsbHMiLAogICAgICAgeCA9ICJOdW1iZXIgb2Ygc2luZ2xlIGNlbGxzIGluIG1ldGFjZWxscyIsCiAgICAgICB5ID0gIk51bWJlciBvZiBjZWxscyB3aXRoIENhcmRpb215b2N5dGUgbGFiZWwiKSAKYGBgCgojIyBDaHJvbVZhciBTY29yZXMgZm9yIFNFQUNlbGxzLCBHQVRBIEZhY3RvcnMKCgpgYGB7ciwgZmlnLndpZHRoPTE1LGZpZy5oZWlnaHQ9MjV9CmRmIDwtIGNvbERhdGEoZGV2KSAlPiUgYXMuZGF0YS5mcmFtZSgpICU+JSByb3duYW1lc190b19jb2x1bW4oIlNFQUNlbGwiKQpkZiA8LSBsZWZ0X2pvaW4oY2VsbHR5cGVfZGYsIGRmLCBieSA9ICJTRUFDZWxsIikKCgpjb2xEYXRhKGRldikgPC0gRGF0YUZyYW1lKGRmKQoKbW90aWZfbXR4IDwtIGFzc2F5cyhkZXYpW1sxXV0KdGZzIDwtIHJvd25hbWVzKGRldikKbWV0YWRhdGEgPC0gY29sRGF0YShkZXYpICU+JSBhcy5kYXRhLmZyYW1lKCkKY29sbmFtZXMobW90aWZfbXR4KSA8LSBtZXRhZGF0YSRTRUFDZWxsCgoKZ2F0YXMgPC0gYygiR2F0YTEiLCAiR2F0YTIiLCAiR2F0YTMiLCAiR2F0YTQiLCAiR2F0YTUiLCAiR2F0YTYiKQoKcGxvdHMgPC0gbWFwIChnYXRhcywgZnVuY3Rpb24obil7CiAgbW90aWZfbiA8LSBtb3RpZl9tdHhbcm93bmFtZXMobW90aWZfbXR4KSA9PSAgdGZzW2dyZXBsKHBhc3RlMCgiXiIsIG4pLCB0ZnMpXSwgXQogIHAyIDwtIG1ldGFkYXRhICU+JQogICAgbXV0YXRlKCEhbiA6PSBtb3RpZl9uKSAlPiUKICAgIGdyb3VwX2J5KGNlbGx0eXBlcykgJT4lCiAgICAjc3VtbWFyaXNlX2F0KHZhcnMobiksIGZ1bnMobWVhbiguLCBuYS5ybT1UUlVFKSkpCiAgICBzdW1tYXJpc2UobWVhbiA9IG1lYW4oISEoc3ltKG4pKSkpICU+JQogICAgZ2dwbG90KCkgKwogICAgZ2VvbV9iYXIoYWVzKHggPSBjZWxsdHlwZXMsIHkgPSBtZWFuLCBmaWxsID0gY2VsbHR5cGVzKSwgc3RhdCA9ICJpZGVudGl0eSIpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvbCkgKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0PTEpLCBsZWdlbmQucG9zaXRpb24gPSAiTm9uZSIpICsjJT4lIHByaW50KCkKICAgIGxhYnMoeSA9ICJTRUFDZWxsIGRldmlhdGlvbiBzY29yZSIpCiAgcDEgPC0gbWV0YWRhdGEgJT4lCiAgICBtdXRhdGUoISFuIDo9IG1vdGlmX24pICU+JQogICAgI2dyb3VwX2J5KFNFQUNlbGwpICU+JSAjLCBjZWxsdHlwZXMpICU+JQogICAgI3N1bW1hcmlzZV9hdCh2YXJzKG4pLCBmdW5zKG1lYW4oLiwgbmEucm09VFJVRSkpKQogICAgI3N1bW1hcmlzZShtZWFuID0gbWVhbighIShzeW0obikpKSkgJT4lCiAgICBnZ3Bsb3QoKSArCiAgICBnZW9tX2JveHBsb3QoYWVzKHggPSBjZWxsdHlwZXMsIHkgPSAhIShzeW0obikpLAogICAgICAgICAgICAgICAgICAgICBmaWxsID0gY2VsbHR5cGVzKSkgKwogICAgZ2VvbV9qaXR0ZXIoYWVzKHggPSBjZWxsdHlwZXMsCiAgICAgICAgICAgICAgICAgICAgeSA9ICEhKHN5bShuKSkpLCBjb2xvcj0iYmxhY2siLCAKICAgICAgICAgICAgICAgIHNpemU9MC40LCBhbHBoYT0wLjkpICsKICAgICMgZ2VvbV9wb2ludChhZXMoeCA9IGNlbGx0eXBlcywgeSA9ICEhKHN5bShuKSkpLAogICAgIyAgICAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gLjUpKSkgKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiTm9uZSIsIAogICAgICAgIGF4aXMudGl0bGUueD1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueD1lbGVtZW50X2JsYW5rKCkpICsKICAgIGxhYnModGl0bGUgPSBwYXN0ZTAobikseSA9ICJTRUFDZWxsIGRldmlhdGlvbiBzY29yZSIpCiAgcGxvdCA8LSBjb3dwbG90OjpwbG90X2dyaWQocDEsIHAyLCBuY29sID0gMSkKfSkKCgpkby5jYWxsKHdoYXQgPSBncmlkRXh0cmE6OmdyaWQuYXJyYW5nZSwgYXJncyA9IGFwcGVuZChwbG90cywgbGlzdChuY29sID0gMikpKQpgYGAKCmBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MjB9Cm4gPSAiR2F0YTEiCm1vdGlmX24gPC0gIG1vdGlmX210eFtyb3duYW1lcyhtb3RpZl9tdHgpID09ICB0ZnNbZ3JlcGwocGFzdGUwKCJeIiwgbiksIHRmcyldLCBdCm1ldGFkYXRhICU+JQogIG11dGF0ZSghIW4gOj0gbW90aWZfbikgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fYmFyKGFlcyh4ID0gU0VBQ2VsbCwgeSA9ICEhKHN5bShuKSkpLCBzdGF0ID0gImlkZW50aXR5Iiwgd2lkdGggPSA1KSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCkgKwogICNzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb2wpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3Q9MSksIGxlZ2VuZC5wb3NpdGlvbiA9ICJOb25lIikgKyMlPiUgcHJpbnQoKQogIGxhYnModGl0bGUgPSBwYXN0ZTAobiksIHkgPSAiU0VBQ2VsbCBkZXZpYXRpb24gc2NvcmUiKSArCiAgZmFjZXRfd3JhcCh+IGNlbGx0eXBlcywgbmNvbCA9IDMpCgptZXRhZGF0YSAlPiUKICBtdXRhdGUoISFuIDo9IG1vdGlmX24pICU+JQogIGZpbHRlcihjZWxsdHlwZXMgPT0gIkNhcmRpb215b2N5dGVzIikKCmBgYAoKCgojIyBGaWx0ZXIgZm9yIHB1cmUgU0VBQ2VsbHMKCiBUbyBjaGVjayB3aHkgdGhlIGRldmlhdGlvbiBzY29yZXMgYXJlIHdvcnNlIHRoYW4gZXhwZWN0ZWQsIEkgcmVtb3ZlZAogYW55IFNFQUNlbGxzIHdoaWNoIGFyZSBsZXNzIHRoYW4gODAlIHB1cmUsIG1lYW5pbmcgdGhhdCBsZXNzIHRoYW4gODAlIG9mIGNlbGxzIAogYmVsb25nIHRvIHRoZSBzYW1lIGNlbGx0eXBlLiAKCmBgYHtyLGZpZy53aWR0aD0xNSxmaWcuaGVpZ2h0PTI1fQpwdXJlX3NlYWNlbGxzIDwtIChzZWFfYXJjaHJfbWV0YSAlPiUgIAogIGRwbHlyOjpncm91cF9ieShTRUFDZWxsKSAlPiUgI2hlYWQKICBtdXRhdGUoY2VsbHNfcGVyX1NFQSA9IG4oKSkgJT4lIAogIHVuZ3JvdXAoKSAlPiUKICBkcGx5cjo6Y291bnQoU0VBQ2VsbCwgY2VsbHR5cGVzLCBjZWxsc19wZXJfU0VBKSAlPiUKICBkcGx5cjo6Z3JvdXBfYnkoU0VBQ2VsbCkgJT4lIAogIG11dGF0ZShwZXJjZW50ID0gbi9jZWxsc19wZXJfU0VBKSAlPiUKICBmaWx0ZXIocGVyY2VudCA+IC44KSkkU0VBQ2VsbAoKcHJpbnQocGFzdGUwKCJPdXQgb2YgIiwgbnJvdyhtZXRhZGF0YSksICIgU0VBQ2VsbHMgb25seSAiLCBsZW5ndGgocHVyZV9zZWFjZWxscyksIAogICAgICAgICAgICAgIiBhcmUgYWJvdmUgODAlIGNvbXBvc2VkIG9mIHRoZSBzYW1lIGNlbGx0eXBlLiIpKQoKCnBsb3RzIDwtIG1hcChnYXRhcywgZnVuY3Rpb24obil7CiAgbW90aWZfbiA8LSBtb3RpZl9tdHhbcm93bmFtZXMobW90aWZfbXR4KSA9PSAgdGZzW2dyZXBsKHBhc3RlMCgiXiIsIG4pLCB0ZnMpXSwgcHVyZV9zZWFjZWxsc10KICBwMiA8LSBtZXRhZGF0YSAlPiUKICAgIGZpbHRlcihTRUFDZWxsICVpbiUgcHVyZV9zZWFjZWxscykgJT4lCiAgICBtdXRhdGUoISFuIDo9IG1vdGlmX24pICU+JQogICAgZ3JvdXBfYnkoY2VsbHR5cGVzKSAlPiUKICAgIHN1bW1hcmlzZShtZWFuID0gbWVhbighIShzeW0obikpKSkgJT4lCiAgICBnZ3Bsb3QoKSArCiAgICBnZW9tX2JhcihhZXMoeCA9IGNlbGx0eXBlcywgeSA9IG1lYW4sIGZpbGwgPSBjZWxsdHlwZXMpLCBzdGF0ID0gImlkZW50aXR5IikgKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0PTEpLCBsZWdlbmQucG9zaXRpb24gPSAiTm9uZSIpKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sKSArCiAgICBsYWJzKCB5ID0gIlNFQUNlbGwgZGV2aWF0aW9uIHNjb3JlIikKICBwMSA8LSBtZXRhZGF0YSAlPiUgICAgCiAgICBmaWx0ZXIoU0VBQ2VsbCAlaW4lIHB1cmVfc2VhY2VsbHMpICU+JQogICAgbXV0YXRlKCEhbiA6PSBtb3RpZl9uKSAlPiUKICAgIGdncGxvdCgpICsKICAgIGdlb21fYm94cGxvdChhZXMoeCA9IGNlbGx0eXBlcywgeSA9ICEhKHN5bShuKSksIGZpbGwgPSBjZWxsdHlwZXMpKSArCiAgICBnZW9tX2ppdHRlcihhZXMoeCA9IGNlbGx0eXBlcywKICAgICAgICAgICAgICAgICAgICB5ID0gISEoc3ltKG4pKSksIGNvbG9yPSJibGFjayIsIAogICAgICAgICAgICAgICAgc2l6ZT0wLjQsIGFscGhhPTAuOSkgKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sKSArCiAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIk5vbmUiLAogICAgICAgIGF4aXMudGl0bGUueD1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueD1lbGVtZW50X2JsYW5rKCkpICsKICAgIGxhYnModGl0bGUgPSBwYXN0ZTAobikseSA9ICJTRUFDZWxsIGRldmlhdGlvbiBzY29yZXMiKQogIHBsb3RzIDwtIGNvd3Bsb3Q6OnBsb3RfZ3JpZChwMSwgcDIsIG5jb2wgPSAxKQp9KQoKZG8uY2FsbCh3aGF0ID0gZ3JpZEV4dHJhOjpncmlkLmFycmFuZ2UsIGFyZ3MgPSBhcHBlbmQocGxvdHMsIGxpc3QobmNvbCA9IDIpKSkKCmBgYAoKCgojIFJOQSBleHByZXNzaW9uCgpgYGAje3J9CiMgYWRkIHJhdyBjb3VudHMgdG8gcHl0aG9uCnJuYV9zZXVyYXQgPC0gcmVhZFJEUygiU2V1cmF0X29iamVjdHMvcm5hX1NldXJhdF9vYmplY3QiKQpyYXdfY291bnRzPC0gcm5hX3NldXJhdEBhc3NheXMkb3JpZ2luYWxleHBAY291bnRzW3JuYV9nZW5lcyRgMGAsIF0Kd3JpdGUuY3N2KHJhd19jb3VudHMsICcvb21pY3MvZ3JvdXBzL09FMDUzMy9pbnRlcm5hbC9rYXRoYXJpbmEvc2NEb1JJL2dhc3RydWxhdGlvbl9kYXRhL2p1cHl0ZXJfbm90ZWJvb2tzL1NFQUNlbGxfZmlsZXMvQXJjaFJfb2JqZWN0L3Jhd19nZW5lX2V4cHIuY3N2JywgcXVvdGU9RkFMU0UpCgoKcm5hX21hdCA8LSByZWFkX2NzdihwYXN0ZTAoZGlyX3BhdGgsICJybmFfYWdnX21hdHJpeC5jc3YiKSkKcm5hX2NlbGxzIDwtIHJlYWRfY3N2KHBhc3RlMChkaXJfcGF0aCwgInJuYV9jZWxsX25hbWVzLmNzdiIpKQpybmFfZ2VuZXMgPC0gcmVhZF9jc3YocGFzdGUwKGRpcl9wYXRoLCAicm5hX2dlbmVfbmFtZXMuY3N2IikpCmRpbShybmFfbWF0KQpybmFfbWF0IDwtIHQocm5hX21hdCkKCnJvd25hbWVzKHJuYV9tYXQpIDwtIHJuYV9nZW5lcyRgMGAKY29sbmFtZXMocm5hX21hdCkgPC0gcm5hX2NlbGxzJGAwYAogIAoKdGVzdCA8LSBTdW1tYXJpemVkRXhwZXJpbWVudChhc3NheXMgPSBsaXN0KGNvdW50cyA9IHJuYV9tYXQpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjcm93UmFuZ2VzID0gZ2VuZV9hbm5vLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xEYXRhID0gRGF0YUZyYW1lKGRmKSkKCiAgCiMgICAKIyAgIAojICMgbm9ybWFsaXplIGNvdW50cwojIG5vcm1fcm5hX21hdCA8LSBsb2cxcCh0KHQocm5hX21hdCkgLyBjb2xTdW1zKHJuYV9tYXQpKSAqIDFlNCkKIyAjcm93bmFtZXMobm9ybV9ybmFfbWF0KSA8LSBybmFfZ2VuZXMkIjAiCiMgY29sbmFtZXMobm9ybV9ybmFfbWF0KSA8LSBybmFfY2VsbHMkIjAiCgpnZW5lX2Fubm8gPC0gZ2V0R2VuZXMocHJvaikgJT4lIGFzLmRhdGEuZnJhbWUoKSAlPiUgCiAgdW5pdGUoaW5kZXgsIHNlcW5hbWVzLCBzdGFydCxzZXAgPSAiOiIsIHJlbW92ZSA9IEZBTFNFKSAlPiUKICB1bml0ZShpbmRleCwgaW5kZXgsIGVuZCwgc2VwID0gIi0iLCByZW1vdmUgPSBGQUxTRSkgJT4lIAogIGZpbHRlcihzeW1ib2wgJWluJSBybmFfZ2VuZXMkIjAiKSMgJT4lICNoZWFkCiAgI2NvbHVtbl90b19yb3duYW1lcyhpbmRleCkKICAjY29sdW1uX3RvX3Jvd25hbWVzKCJpbmRleCIpICU+JQogIyBHUmFuZ2VzKCkKCnJuYV9zY2UgPC0gU3VtbWFyaXplZEV4cGVyaW1lbnQoYXNzYXlzID0gbGlzdChjb3VudHMgPSBybmFfbWF0KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICByb3dEYXRhID0gZ2VuZV9hbm5vLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjcm93UmFuZ2VzID0gZ2VuZV9hbm5vLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xEYXRhID0gRGF0YUZyYW1lKGRmKSkKCgoKCnJuYV9tYXQgPC0gYXNzYXlzKHJuYV9zY2UpW1sxXV0KCm1ldGFkYXRhIDwtIGNvbERhdGEocm5hX3NjZSkgJT4lIGFzLmRhdGEuZnJhbWUoKQoKZ2F0YXMgPC0gYygiR2F0YTEiLCAiR2F0YTIiLCAiR2F0YTMiLCAiR2F0YTQiLCAiR2F0YTUiLCAiR2F0YTYiKQoKZm9yIChuIGluIGdhdGFzKXsKICBtb3RpZl9uIDwtIHJuYV9tYXRbcm93bmFtZXMocm5hX21hdCkgPT0gIG4sIF0jdGZzW2dyZXBsKHBhc3RlMCgiXiIsIG4pLCB0ZnMpXSwgXQogIHAgPC0gbWV0YWRhdGEgJT4lCiAgICBtdXRhdGUoISFuIDo9IG1vdGlmX24pICU+JQogICAgZ3JvdXBfYnkoY2VsbHR5cGVzKSAlPiUKICAgICNzdW1tYXJpc2VfYXQodmFycyhuKSwgZnVucyhtZWFuKC4sIG5hLnJtPVRSVUUpKSkKICAgIHN1bW1hcmlzZShtZWFuID0gbWVhbighIShzeW0obikpKSkgJT4lCiAgICBnZ3Bsb3QoKSArCiAgICBnZW9tX2JhcihhZXMoeCA9IGNlbGx0eXBlcywgeSA9IG1lYW4sIGZpbGwgPSBjZWxsdHlwZXMpLCBzdGF0ID0gImlkZW50aXR5IikgKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sKSArCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3Q9MSksIGxlZ2VuZC5wb3NpdGlvbiA9ICJOb25lIikgKyMlPiUgcHJpbnQoKQogICAgbGFicyh0aXRsZSA9IHBhc3RlMChuKSwgeSA9ICJTRUFDZWxsICBzY29yZSIpCiAgcHJpbnQocCkKfQpgYGAKCgoKCgoK